﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using System.IO;
using System.Xml;
using System.Collections;
using Reborn_Server.App1AppHandler;
using System.Drawing;
using Reborn_WorldServer.App1AppHandler;
using Reborn_WorldServer.App1AppHandler.Spells.Interfaces;
using Reborn_WorldServer;

namespace App1AppHandler
{
    public class CreatureBase
    {
        //copies this classes starting properties to the copy creature.
        virtual public void copyFrom(CreatureBase copyFromCreature)
        {
            this.CreatureType = copyFromCreature.CreatureType;

            //this.CreatureID = Managers.GameHandler.ItemIDGen.GetCreatureUID();

            this.ID = copyFromCreature.ID;
            this.HPRegen = copyFromCreature.HPRegen;
            this.ManaRegen = copyFromCreature.ManaRegen;

            //copyFromCreature.WaterMotion

            this.MaxHPBase = copyFromCreature.MaxHPBase;
            this.MaxStaminaBase = copyFromCreature.MaxStaminaBase;
            this.MaxManaBase = copyFromCreature.MaxManaBase;

            //this.StartMapX = copyFromCreature.StartMapX;
            //this.StartMapY = copyFromCreature.StartMapY;
            //this.StartMapID = copyFromCreature.StartMapID;

            this.Instance = copyFromCreature.Instance;

            //this.StartLeftHand = copyFromCreature.StartLeftHand;
            //this.StartRightHand = copyFromCreature.StartRightHand;

            this.Air = copyFromCreature.Air;
            this.Water = copyFromCreature.Water;
            this.Land = copyFromCreature.Land;

            this.CorpseImageURL = copyFromCreature.CorpseImageURL;
            this.Faction = copyFromCreature.Faction;
            this.ImageURL = copyFromCreature.ImageURL;
            this.Name = copyFromCreature.Name;

            //this.MaxMoves = copyFromCreature.MaxMoves;            
            //this.Respawn_Min = copyFromCreature.Respawn_Min;

            this.SoundDeath = copyFromCreature.SoundDeath;
            this.Name = copyFromCreature.Name;

            //this.WanderMax_N = copyFromCreature.WanderMax_N;
            //this.WanderMax_E = copyFromCreature.WanderMax_E;
            //this.WanderMax_S = copyFromCreature.WanderMax_S;
            //this.WanderMax_W = copyFromCreature.WanderMax_W;

            //this.CoinsLow = copyFromCreature.CoinsLow;
            //this.CoinsHigh = copyFromCreature.CoinsHigh;

            //this.buffManager.HasInnateNightVision = copyFromCreature.buffManager.HasInnateNightVision;

            //this.RushAttack = copyFromCreature.RushAttack;
            //this.RangeAttack = copyFromCreature.RangeAttack;
            //this.Defense = copyFromCreature.Defense;
            //this.DefenseSkill = copyFromCreature.DefenseSkill;
            //this.HandBlockWeapon = copyFromCreature.HandBlockWeapon;
            //this.SoundEnterCombat = copyFromCreature.SoundEnterCombat;
            //this.RunHPPercent = copyFromCreature.RunHPPercent;

            //this.BaseMovementSpeed = copyFromCreature.BaseMovementSpeed;
            //this.MovementSpeed = copyFromCreature.BaseMovementSpeed;

            this.Intelligence = copyFromCreature.Intelligence;
            this.Wisdom = copyFromCreature.Wisdom;
            this.Strength = copyFromCreature.Strength;
            this.Agility = copyFromCreature.Agility;
            this.Dexterity = copyFromCreature.Dexterity;

            //this.BaseResistFire = copyFromCreature.BaseResistFire;
            //this.ResistFire = copyFromCreature.ResistFire;

            //this.BaseResistIce = copyFromCreature.BaseResistIce;
            //this.ResistIce = copyFromCreature.ResistIce;

            //this.BaseResistHoly = copyFromCreature.BaseResistHoly;
            //this.ResistHoly = copyFromCreature.ResistHoly;

            //this.BaseResistUnholy = copyFromCreature.BaseResistUnholy;
            //this.ResistUnholy = copyFromCreature.ResistUnholy;

            //this.BaseResistMagic = copyFromCreature.BaseResistMagic;
            //this.ResistMagic = copyFromCreature.ResistMagic;

            //this.BaseResistPhysical = copyFromCreature.BaseResistPhysical;
            //this.ResistPhysical = copyFromCreature.ResistPhysical;

            this.Armor = copyFromCreature.Armor;

            //this.IgnoresFire = copyFromCreature.IgnoresFire;
            //this.IgnoresIce = copyFromCreature.IgnoresIce;
            //this.IgnoresHoly = copyFromCreature.IgnoresHoly;
            //this.IgnoresUnholy = copyFromCreature.IgnoresUnholy;
            //this.IgnoresMagic = copyFromCreature.IgnoresMagic;

            //this.Smart = copyFromCreature.Smart;
            //setXmlData(copyFromCreature.xmlData);
        }


        //Data for Client
        public long CreatureID = -1;
        public string Name = "";
        public string ImageURL = "";

        //This object is used to lock the creature when the creature may be changing maps (map lock could fail due to creature being moved)
        //Current Occurances (CreatureAI, Dismiss Pet)
        public Object creatureLock = new Object();

        volatile protected Loot _LeftHand;
        public virtual Loot LeftHand
        {
            set
            {
                _LeftHand = value;

                Buff hideBuff = buffManager.GetBuffByStackType("Hide");
                if (hideBuff != null)
                {
                    if (_LeftHand != null)
                    {
                        bool isRange = false;
                        bool isMelee = false;
                        if (_LeftHand is Weapon)
                        {
                            Weapon leftHandWeapon = (Weapon)_LeftHand;
                            isRange = leftHandWeapon.Range;
                            isMelee = leftHandWeapon.Melee;
                        }
                        bool canHideWith = false;
                        if (_LeftHand.Bag == true)
                            canHideWith = true;
                        if (isRange == true && isMelee == false)
                            canHideWith = true;

                        if (canHideWith == false)
                        {
                            SendMessage("You have picked up a weapon you cannot hide with!", "server");
                            if (this is Character)
                            {
                                Character myChar = (Character)this;
                                myChar.PlaySound("Ding", myChar.MapX, myChar.MapY);
                            }
                            hideBuff.RemoveSpell(true, true);
                        }
                    }
                }
            }
            get
            {
                return _LeftHand;
            }
        }
        volatile protected Loot _RightHand;
        public virtual Loot RightHand
        {
            set
            {
                _RightHand = value;

                Buff hideBuff = buffManager.GetBuffByStackType("Hide");
                if (hideBuff != null)
                {
                    if (_RightHand != null)
                    {
                        bool isRange = false;
                        bool isMelee = false;
                        if (_RightHand is Weapon)
                        {
                            Weapon rightHandWeapon = (Weapon)_RightHand;
                            isRange = rightHandWeapon.Range;
                            isMelee = rightHandWeapon.Melee;
                        }
                        bool canHideWith = false;
                        if (_RightHand.Bag == true)
                            canHideWith = true;
                        if (isRange == true && isMelee == false)
                            canHideWith = true;

                        if (canHideWith == false)
                        {
                            SendMessage("You have picked up a weapon you cannot hide with!", "server");
                            if (this is Character)
                            {
                                Character myChar = (Character)this;
                                myChar.PlaySound("Ding", myChar.MapX, myChar.MapY);
                            }
                            hideBuff.RemoveSpell(true, true);
                        }
                    }
                }
            }
            get
            {
                return _RightHand;
            }
        }

        public int MaxHPBase = 0;
        public int MaxHPAdd = 0;
        public int MaxHP
        {
            get 
            {
                int value = MaxHPBase + MaxHPAdd;
                if (value < 1)
                    return 1;

                return value; 
            }
        }

        private volatile int _HP = 0;
        public virtual int HP {
            get {
                return _HP;
            }
            set {
                if (value > MaxHP)
                    value = MaxHP;
                if (value < 0)
                    value = 0;

                _HP = value;

                if (_HP < 1)
                {
                    List<Buff> buffs = buffManager.Buffs;
                    foreach (Buff buff in buffs)
                    {
                        if (!(buff is IDeathEffect))
                            buff.RemoveSpell(false, false);
                    }
                    buffManager.UpdateBuffs();

                    //Dont try to dismiss a quest creature, master does not have actual control
                    if (petController != null && !(this is QuestCreature))
                        petController.Dismiss();
                }
            }
        }

        public int MaxStaminaBase = 0;
        public int MaxStaminaAdd = 0;
        public int MaxStamina
        {
            get 
            {
                int value = MaxStaminaBase + MaxStaminaAdd;
                if (value < 1)
                    return 1;

                return value;
            }
        }

        private int _Stamina = 0;
        public virtual int Stamina {
            get {
                return _Stamina;
            }
            set {
                if (value > MaxStamina)
                    value = MaxStamina;
                if (value < 0)
                    value = 0;

                _Stamina = value;
            }
        }

        public int MaxManaBase = 0;
        public int MaxManaAdd = 0;
        public int MaxMana
        {
            get 
            {
                int value = MaxManaBase + MaxManaAdd;
                if (value < 1)
                    return 1;

                return value; 
            }
        }

        private int _Mana = 0;
        public virtual int Mana {
            get {
                return _Mana;
            }
            set {
                if (value > MaxMana)
                    value = MaxMana;
                if (value < 1)
                    value = 0;

                _Mana = value;
            }
        }

        

        //Heals from ice damage
        public bool IceEater = false;

        public int ManaRegen = 10;
        public int StaminaRegen = 10;
        public int HPRegen = 10;


        protected string Timer_HexDamageType = "";
        protected int Timer_HexDamageCounter = -1;
        protected Timer Timer_HexDamage = new Timer(1500);
        protected void Timer_HexDamage_Start(string DamageType)
        {
            Timer_HexDamageCounter = 0;
            Timer_HexDamageType = DamageType;
            Timer_HexDamage.Start();
        }
        protected bool Timer_HexDamage_Stop()
        {
            try
            {
                Timer_HexDamage.Stop();
            }
            catch
            {
                Timer_HexDamageCounter = -1;
                return false;
            }
            if (Timer_HexDamageCounter == -1)
                return false;

            Timer_HexDamageCounter = -1;
            return true;
        }

        public virtual void InflictDamage(int Damage, int AttackingCharacterID)
        {
            List<Character> charactersWithin8 = currentMapItem.getCharactersWithin8();

            if (WarmSpell != null && Damage > 0)
            {
                int modifiedHP = this.HP + (this.WisdomTotal * 3);
                double fizzleChancePercent = System.Convert.ToDouble(Damage) / System.Convert.ToDouble(modifiedHP);
                fizzleChancePercent = (fizzleChancePercent * 1.3) * 100;

                double fizzleResult = GameHandler.random.Next(1, 100001);
                fizzleResult = fizzleResult / 1000;

                if (fizzleResult < fizzleChancePercent)
                {
                    //Try for an exceptional balance recovery
                    bool useExceptionalBalance = false;
                    if (this is Character)
                    {
                        Character thisCharacter = (Character)this;
                        useExceptionalBalance = thisCharacter.weaponSkillManager.useExceptionalBalance();
                    }

                    if (useExceptionalBalance == false)
                    {
                        WarmSpell = null;
                        foreach (Character character in charactersWithin8)
                        {
                            if (Math.Abs(character.MapX - MapX) <= 8 && Math.Abs(character.MapY - MapY) <= 4)
                                character.PlaySound("SpellFizzle", MapX, MapY);
                        }
                        if (this is Character)
                        {
                            Message msg = new Message();
                            msg.Type = "server";
                            msg.CreatureID = this.CreatureID;
                            msg.Text = "Your spell has been fizzled!";
                            Character character = (Character)this;
                            character.AddMessage(msg);
                        }
                    }
                    else
                    {
                        SendMessage("You regain your balance!", "server");
                    }
                }
            }

            //This will remove buffs with no message if the character is dead
            this.HP = this.HP - Damage;

            if (Damage > 0)
            {
                Buff freeze = buffManager.GetBuffByStackType("FreezingAura");
                if (freeze != null && freeze.spellIcon.Offensive == true) freeze.RemoveSpell(true, true);

                Buff mezz = buffManager.GetBuffByStackType("Mesmerize");
                if (mezz != null) mezz.RemoveSpell(true, true);

                Buff invis = buffManager.GetBuff("Invisibility");
                if (invis != null) invis.RemoveSpell(true, true);

                Buff hide = buffManager.GetBuffByStackType("Hide");
                if (hide != null) hide.RemoveSpell(true, true);
            }

            if (this.HP < 1)
            {
                DropLoot(AttackingCharacterID);

                if (WarmSpell != null)
                {
                    WarmSpell = null;
                    foreach (Character character in charactersWithin8)
                    {
                        if (Math.Abs(character.MapX - MapX) <= 8 && Math.Abs(character.MapY - MapY) <= 4)
                            character.PlaySound("SpellFizzle", MapX, MapY);
                    }
                }

                if (this is Character)
                {
                    Character tempThis = (Character)this;
                    tempThis.Timer_Respawn.Start();
                }
                else
                    this.currentMapItem.CreaturesBases.Remove(this);

                if (this is Creature && hateManager != null)
                    hateManager.ClearAllHateInfo();

                foreach (Character character in charactersWithin8)
                {
                    if (Math.Abs(character.MapX - MapX) <= 8 && Math.Abs(character.MapY - MapY) <= 8)
                        character.PlaySound(this.SoundDeath, this.MapX, this.MapY);
                }

            }
        }

        public virtual void InflictSpellDamage(int Damage, int AttackingCharacterID, long AttackingCreatureGUID, string damageType, out int absorbed)
        {
            if (damageType == "Ice" && IceEater == true)
            {
                if (this.petController == null || (this.petController != null && this.petController.MasterCreature is Character && this.petController.MasterCreature.ID == AttackingCharacterID))
                {
                    absorbed = Damage;
                    HP = HP + Damage;
                    return;
                }
            }

            int result = Damage;
            int totalDamage = Damage;
            absorbed = 0;

            IDamageAbsorbBuff dmgAbsorb = buffManager.GetDamageAbsorbBuff();
            if (dmgAbsorb != null)
            {
                result = dmgAbsorb.AbsorbDamageReturnRemainder(result);
                absorbed = totalDamage - result;
            }

            //Pass -1 for master since pets cant cast spells yet.
            if (this is Creature)
            {
                hateManager.UpdateList(AttackingCharacterID,
                    AttackingCharacterID == -1 ? AttackingCreatureGUID : -1,
                    result,
                    -1);
            }
            
            if (result > 0)
                InflictDamage(result, AttackingCharacterID);

            if (result > 0)
            {
                Spell_BleedingWounds buff = (Spell_BleedingWounds)this.buffManager.GetBuff("Mana Burn");
                if (buff != null)
                    buff.AddDamage();
            }
        }

        public int CalculateGetSpellDamagePerResists(int Damage, string Type, decimal PercentOfResist)
        {
            int resist = getResist(Type);
            resist = System.Convert.ToInt32(resist * PercentOfResist);

            return CalculateDamage(Damage, resist);
        }
        public int CalculateGetSpellDamagePerResists(int Damage, string Type)
        {
            int resist = getResist(Type);

            return CalculateDamage(Damage, resist);
        }
        protected virtual int CalculateDamage(int Damage, int resist)
        {
            //int resist = getResist(Type);

            int result = Damage;
            if (resist <= (Damage / 2))
                result = Damage - resist;
            else
            {
                result = Damage / 2;

                int ResistOverHalf = resist - (Damage / 2);
                double ratio = (ResistOverHalf / (Damage / 2.00)) + 1;
                double reduction = ResistOverHalf / ratio;

                result = result - System.Convert.ToInt32(System.Math.Floor(reduction));
            }

            return result;
        }


        static public int calculateDamageAfterArmor(int Damage, int armorValue)
        {
            int result = Damage;
            if (armorValue <= (Damage / 2))
                result = Damage - armorValue;
            else
            {
                result = Damage / 2;

                int ArmorOverHalf = armorValue - (Damage / 2);
                double ratio = (ArmorOverHalf / (Damage / 2.00)) + 1;
                double reduction = ArmorOverHalf / ratio;

                result = result - System.Convert.ToInt32(System.Math.Floor(reduction));
            }
            return result;
        }

        private int calculateArmorAfterPiercing(int armorValue, int piercing)
        {
            if (armorValue < 1)
                return 0;

            int result = armorValue;

            double ratio = (System.Convert.ToDouble(piercing) / System.Convert.ToDouble(armorValue)) + 1.00;
            double reduction = piercing / ratio;

            result = result - System.Convert.ToInt32(System.Math.Floor(reduction));

            return result;
        }

        //Calculates damage reduction per armor, returns damage after modification, and absorbed ammout (If has absorb buff)
        public virtual int InflictDamageArmorReduce(int Damage, CreatureBase AttackingCreatureBase, out int Absorbed, bool useRange, double multiplier, int armorPiercing)
        {
            int armorValue = ArmorTotal;

            armorValue = calculateArmorAfterPiercing(armorValue, armorPiercing);

            armorValue = System.Convert.ToInt32(armorValue * multiplier);
            Damage = System.Convert.ToInt32(Damage * multiplier);

            List<Character> charactersWithin4 = currentMapItem.getCharactersWithin4();

            Absorbed = 0;

            int result = CreatureBase.calculateDamageAfterArmor(Damage, armorValue);

            if (useRange == false)
            {
                Buff dmgShield = buffManager.GetBuff("Flame Shield");
                if (dmgShield != null)
                {
                    Spell_FlameShield flameShield = (Spell_FlameShield)dmgShield;
                    int dmg = flameShield.GetDamage();

                    AttackingCreatureBase.InflictDamage(dmg, this is Creature ? -1 : this.ID);

                    if (AttackingCreatureBase is Creature)
                        AttackingCreatureBase.hateManager.UpdateList(this, dmg);

                    if (AttackingCreatureBase is Character)
                    {
                        Character character = (Character)AttackingCreatureBase;

                        Message msg = new Message();
                        msg.CreatureID = AttackingCreatureBase.CreatureID;
                        msg.Type = "damaged";
                        msg.Text = "You have been burned by " + this.Name + " (" + dmg.ToString() + ")";

                        character.AddMessage(msg);
                    }
                    if (this is Character)
                    {
                        Character character = (Character)this;

                        Message msg = new Message();
                        msg.CreatureID = character.CreatureID;
                        msg.Type = "damage";
                        msg.Text = "You burn " + AttackingCreatureBase.Name + " (" + dmg.ToString() + ")";

                        character.AddMessage(msg);
                    }
                    if (AttackingCreatureBase.HP < 1)
                    {
                        foreach (Character character in charactersWithin4)
                        {
                            character.AddMapItem(AttackingCreatureBase.currentMapItem);
                        }
                    }
                    else
                    {
                        foreach (Character character in charactersWithin4)
                        {
                            character.AddCreatureBase(AttackingCreatureBase);
                        }
                    }
                }

                if (AttackingCreatureBase.HP > 0)
                {
                    Buff reflectDamageBuff = buffManager.GetBuff("Reflect Damage");
                    if (reflectDamageBuff != null && AttackingCreatureBase.HP > 0)
                    {
                        Spell_ReflectDamage reflectDamage = (Spell_ReflectDamage)reflectDamageBuff;
                        result = reflectDamage.reflectDamageReturnRemainder(AttackingCreatureBase, result);
                    }
                }

                if (AttackingCreatureBase.HP > 0)
                {
                    Buff explodingAuraBuff = buffManager.GetBuff("Exploding Aura Rank 2");
                    if (explodingAuraBuff == null)
                        explodingAuraBuff = buffManager.GetBuff("Exploding Aura");
                    if (explodingAuraBuff != null && AttackingCreatureBase.HP > 0)
                    {
                        Spell_ExplodingAura explodingAura = (Spell_ExplodingAura)explodingAuraBuff;
                        explodingAura.trigger(AttackingCreatureBase);
                    }
                }

                if (AttackingCreatureBase.HP > 0)
                {
                    Buff freezeBuff = buffManager.GetBuffByStackType("FreezingAura");
                    if (freezeBuff != null && freezeBuff.spellIcon.Offensive == false)
                    {
                        Spell_FreezingAura freeze = (Spell_FreezingAura)freezeBuff;
                        freeze.tryFreeze(AttackingCreatureBase);
                    }
                }
            }



            int totalDamage = result;
            IDamageAbsorbBuff dmgAbsorb = buffManager.GetDamageAbsorbBuff();
            if (dmgAbsorb != null)
            {
                result = dmgAbsorb.AbsorbDamageReturnRemainder(result);
                Absorbed = totalDamage - result;
            }

            //If we're a creature, update the total hate on us
            if (this is Creature)
                hateManager.UpdateList(AttackingCreatureBase, totalDamage);

            //If the attacker is somethings pet, get the attacking characterID from the master
            int attackingCharacterId = -1;
            if (AttackingCreatureBase.petController != null)
            {
                if (AttackingCreatureBase.petController.MasterCreature is Character)
                    attackingCharacterId = AttackingCreatureBase.petController.MasterCreature.ID;
            }
            //Not a pet, just get characterID
            else
            {
                if (AttackingCreatureBase is Character)
                    attackingCharacterId = AttackingCreatureBase.ID;
            }

            InflictDamage(result, attackingCharacterId);

            if (HP < 1)
                AttackingCreatureBase.hateManager.ClearHateInfo(this);

            if (result > 0)
            {
                Buff bleedingWoundsBuff = this.buffManager.GetBuffByStackType("BleedingWounds");
                if (bleedingWoundsBuff != null)
                {
                    Spell_BleedingWounds bleedingWounds = (Spell_BleedingWounds)bleedingWoundsBuff;
                    bleedingWounds.AddDamage();
                }

                if (useRange == false)
                {
                    //Check if attacker has vamp buff
                    Buff vampBuff = AttackingCreatureBase.buffManager.GetBuffByStackType("VampiricTouch");
                    if (vampBuff != null)
                    {
                        Spell_VampiricTouch spell_vampBuff = (Spell_VampiricTouch)vampBuff;
                        if (spell_vampBuff.runEffect(result) == true)
                        {
                            foreach (Character character in charactersWithin4)
                            {
                                if (Math.Abs(character.MapX - AttackingCreatureBase.MapX) <= 4 && Math.Abs(character.MapY - AttackingCreatureBase.MapY) <= 4)
                                {
                                    character.UpdateCreatureBaseHp(AttackingCreatureBase);
                                    character.UpdateCreatureBaseHp(this);
                                }
                            }
                        }
                    }
                }
            }

            Buff webBuff = buffManager.GetBuffByStackType("Web");
            while (webBuff != null)
            {
                webBuff.RemoveSpell(true, true);
                webBuff = buffManager.GetBuffByStackType("Web");
            }

            return result;           
        }

        //This will be overriden in subclasses to try to block incoming damage
        //Returns "" if no block, if successfully block returns blocking weapons name
        public virtual string DamageBlock(int Accuracy, CreatureBase AttackingCreatureBase, out bool parry)
        {
            parry = false;

            return "";
        }

        public int Strength = 0;
        public int Dexterity = 0;
        public int Agility = 0;
        public int Intelligence = 0;
        public int Wisdom = 0;

        public int Armor = 0;
        public int ArmorTotal
        {
            get
            {
                if (Armor < 0)
                    return 0;

                return Armor;
            }
        }

        public bool Land = true;
        public bool Water = true;
        public bool Air = true;

        public int ResistFire = 0;
        public int ResistIce = 0;
        public int ResistHoly = 0;
        public int ResistUnholy = 0;
        public int ResistMagic = 0;
        public int ResistPhysical = 0;

        public int getResist(string type)
        {
            switch (type)
            {
                case "Fire":
                    if (ResistFire < 0)
                        return 0;

                    return ResistFire;
                case "Ice":
                    if (ResistIce < 0)
                        return 0;

                    return ResistIce;
                case "Holy":
                    if (ResistHoly < 0)
                        return 0;

                    return ResistHoly;
                case "Unholy":
                    if (ResistUnholy < 0)
                        return 0;

                    return ResistUnholy;

                case "Mentality":
                    if (ResistMagic < 0)
                        return 0;

                    return ResistMagic;

                case "Magic":
                    if (ResistMagic < 0)
                        return 0;

                    return ResistMagic;

                default:
                    if (ResistPhysical < 0)
                        return 0;

                    return ResistPhysical;
            }
        }

        
        public int StrengthAdd = 0;
        public int DexterityAdd = 0;
        public int AgilityAdd = 0;
        public int IntelligenceAdd = 0;
        public int WisdomAdd = 0;

        public int StrengthTotal
        {
            get 
            {
                if (Strength + StrengthAdd < 0)
                    return 0;

                return Strength + StrengthAdd; 
            }
        }
        public int DexterityTotal
        {
            get 
            {
                if (Dexterity + DexterityAdd < 0)
                    return 0;

                return Dexterity + DexterityAdd; 
            }
        }
        public int AgilityTotal
        {
            get 
            {
                if (Agility + AgilityAdd < 0)
                    return 0;

                return Agility + AgilityAdd; 
            }
        }
        public int IntelligenceTotal
        {
            get 
            {
                if (Intelligence + IntelligenceAdd < 0)
                    return 0;

                return Intelligence + IntelligenceAdd; 
            }
        }
        public int WisdomTotal
        {
            get 
            {
                if (Wisdom + WisdomAdd < 0)
                    return 0;

                return Wisdom + WisdomAdd; 
            }
        }

        public string Faction = "";

        //Read only function, calculates the MovementModifier, -60 minimum (we cant have instant moves)
        private double _MovementSpeed = 3;
        public double MovementSpeed
        {
            set { _MovementSpeed = value; }
            get 
            {
                int modifier = MovementSpeedPercentModifier;
                if (modifier < -60) modifier = -60;
                return _MovementSpeed + (_MovementSpeed * (modifier / 100.00));
            }
        }

        //Modifiers are negative for a bonus (decreases times), and positive for a penalty (increases times)
        public int MovementSpeedPercentModifier = 0;
        public int CastingSpeedPercentModifier = 0;
        public int RangeSpeedPercentModifier = 0;
        public int MeleeSpeedPercentModifier = 0;

        volatile public BuffManager buffManager;
        volatile public HateManager hateManager;

        //This is set if the creature is acting as a pet
        volatile public Pet_Controller petController = null;

        private int _MapX = -1;
        private int _MapY = -1;
        private int _MapID = -1;

        //Map locking methods cannot execute when a creature is in the middle of changing maps (its position cannot be guarenteed correct)
        //This stores a queue of methods that attempted to execute durring a map change. They will be invoked on separate threads when the change is complete
        private List<PendingMethod> pendingMethods = new List<PendingMethod>();
        private bool _isChangingMaps = false;
        private Object changingMapsLock = new Object();
        //This is the signature of Delegate.DynamicInvoke - DynamicInvoke is syncronous so we use this delegate to call DynamicInvoke asyncronously.
        private delegate object AsyncDynamicInvoke(Object[] args);
        public void setIsChangingMaps(bool value)
        {
            lock (changingMapsLock)
            {
                _isChangingMaps = value;
                if (_isChangingMaps == false)
                {
                    while (pendingMethods.Count > 0)
                    {
                        AsyncDynamicInvoke asyncDynamicInvoke = (AsyncDynamicInvoke)pendingMethods[0].method.DynamicInvoke;
                        //Call BeginInvoke on DynamicInvoke to run it asyncronously
                        asyncDynamicInvoke.BeginInvoke(pendingMethods[0].args, null, null);
                        pendingMethods.RemoveAt(0);
                    }
                }
            }
        }
        //We pass the method we're trying to run + args when checking if we're mid transfer. If we are, the method and args get recorded and will run when the transfer is complete.
        public bool isChangingMaps(Delegate method, Object[] args)
        {
            lock (changingMapsLock)
            {
                if (_isChangingMaps == true)
                {
                    pendingMethods.Add(new PendingMethod(method, args));
                    return true;
                }
                return false;
            }
        }


        public int MapX
        {
            get
            {
                lock (currentMapItemLock)
                {
                    return _MapX;
                }
            }
        }
        public int MapY
        {
            get
            {
                lock (currentMapItemLock)
                {
                    return _MapY;
                }
            }
        }

        private Object currentMapItemLock = new Object();
        private MapItem _currentMapItem = null;
        public MapItem currentMapItem
        {
            get 
            {
                lock (currentMapItemLock)
                {
                    return _currentMapItem;
                }
            }
        }


        //Counter used for regen to start reducing mana due to spell being warmed to long
        private int warmSpellCounter = 0;
        public QueueTimer Timer_Regen = new QueueTimer(7500);

        public virtual void SetPosition(MapItem mapItem)
        {
            lock (currentMapItemLock)
            {
                bool changingMaps = false;

                if (currentMapItem == null || currentMapItem.parentMap.MapID != mapItem.parentMap.MapID)
                    changingMaps = true;

                if (changingMaps == true && currentMapItem != null)
                    currentMapItem.parentMap.removeCreatureToProcess(this);

                _currentMapItem = mapItem;

                _MapID = mapItem.parentMap.MapID;
                _MapX = mapItem.MapX;
                _MapY = mapItem.MapY;

                if (changingMaps == true)
                    currentMapItem.parentMap.addCreatureToProcess(this);
            }
        }

        public virtual int MapID
        {
            set 
            {
                lock (currentMapItemLock)
                {
                    _MapID = value;
                }
            }
            get 
            {
                lock (currentMapItemLock)
                {
                    return _MapID;
                }
            }
        }

        public int Instance = -1;
        public string CreatureType = "";
        volatile public SpellIcon WarmSpell;

        //Data For Server
        public int ID = -1;
        public string SoundDeath = "";
        public string CorpseImageURL = "";
        public int Coins = 0;
        public AppHandler2 GameHandler;

        //Constructor, sets references to main App and intializes and managers and sets creature reference for manager
        public CreatureBase(AppHandler2 app) 
        {
            GameHandler = app;
            CreatureBase cb = this;
            buffManager = new BuffManager(cb);
            hateManager = new HateManager(cb);

            //Timer_Regen.AutoReset = true;
            //Timer_Regen.Elapsed += new ElapsedEventHandler(Timer_Regen_Elapsed);

            Timer_HexDamage.AutoReset = false;
            Timer_HexDamage.Elapsed += new ElapsedEventHandler(Timer_HexDamage_Elapsed);
        }

        virtual protected void Timer_HexDamage_Elapsed(object sender, ElapsedEventArgs e)
        {
            Timer_HexDamageCounter++;
        }

        public virtual void DropLoot(int SlayingCharID)
        {
            buffManager.runAndRemoveDeathEffectBuffs();
        }

        public string toXML(Character sendingToCharacter)
        {
            string result = "";

            StringWriter stringWriter = new StringWriter();
            XmlTextWriter xmldoc = new XmlTextWriter(stringWriter);

            xmldoc.WriteStartElement("c");
            xmldoc.WriteAttributeString("a", CreatureID.ToString());
            xmldoc.WriteAttributeString("b", CreatureType.ToString());

            if (sendingToCharacter.hateManager.GetCreatureHateInfo(this) != null)
                xmldoc.WriteAttributeString("c", "Hostile");
            else
                xmldoc.WriteAttributeString("c", Faction.ToString());            
            
            xmldoc.WriteAttributeString("d", HP.ToString());

            if (this is Character)
            {
                Character thisCharacter = (Character)this;
                CharacterColorOverride cco = thisCharacter.getColorOverride(thisCharacter.currentColor);
                if (cco != null)
                    xmldoc.WriteAttributeString("e", cco.imageName);
                else
                    xmldoc.WriteAttributeString("e", ImageURL.ToString());
            }
            else
                xmldoc.WriteAttributeString("e", ImageURL.ToString());


            xmldoc.WriteAttributeString("f", Instance.ToString());
            
            xmldoc.WriteAttributeString("g", MapID.ToString());
            xmldoc.WriteAttributeString("h", MapX.ToString());
            xmldoc.WriteAttributeString("i", MapY.ToString());
            xmldoc.WriteAttributeString("j", MaxHP.ToString());
            xmldoc.WriteAttributeString("k", Name.ToString());

            if (sendingToCharacter.Faction == this.Faction)
            {
                xmldoc.WriteAttributeString("l", MaxStamina.ToString());
                xmldoc.WriteAttributeString("m", Stamina.ToString());

                xmldoc.WriteAttributeString("n", Mana.ToString());
                xmldoc.WriteAttributeString("o", MaxMana.ToString());
            }
            else
            {
                xmldoc.WriteAttributeString("l", "-1");
                xmldoc.WriteAttributeString("m", "-1");

                xmldoc.WriteAttributeString("n", "-1");
                xmldoc.WriteAttributeString("o", "-1");
            }

            xmldoc.WriteAttributeString("p", buffManager.HasHide().ToString());

            xmldoc.WriteStartElement("q");
            if (LeftHand != null)
                xmldoc.WriteRaw(LeftHand.toXML(sendingToCharacter));
            xmldoc.WriteEndElement();

            xmldoc.WriteStartElement("r");
            if (RightHand != null)
                xmldoc.WriteRaw(RightHand.toXML(sendingToCharacter));
            xmldoc.WriteEndElement();

            xmldoc.WriteStartElement("s");
            List<Buff> buffs = buffManager.Buffs;
            foreach (Buff buff in buffs)
                xmldoc.WriteRaw(buff.spellIcon.toXML());
            xmldoc.WriteEndElement();

            xmldoc.WriteEndElement();
            xmldoc.Flush();

            xmldoc.Close();

            stringWriter.Flush();

            result = stringWriter.ToString();

            return result;
        }

        public void runRegen()
        {
            Timer_Regen.Start();

            LockItem lockitem = GameHandler.GetLockItem(MapID, Instance);
            lock (lockitem.LockObj)
            {
                //CHECK IF WE'RE IN A VALID STATE TO CONTINUE EXECUTION/////////////////////////

                //System.Reflection.MethodBase currentMethodBase = System.Reflection.MethodBase.GetCurrentMethod();
                //Delegate currentMethodDelegate = Delegate.CreateDelegate(currentMethodBase.GetType(), this, currentMethodBase.Name);

                //Create a delegate for this method incase it cant be run right now
                Action thisMethod = (Action)runRegen;
                //Record this method's arguments
                Object[] thisMethodArgs = { null };
                //Pass the delegate and args when we check if we're mid map transfer. If yes, they will be recorded and run again automatically.
                if (this.isChangingMaps(thisMethod, thisMethodArgs) == true)
                    return;

                //A map transfer happened, but its already complete. Immediately re-run this method on a different thread. 
                //We need to use a different thread because otherwise the current thread would lock 2 maps possibly resulting in a deadlock.
                if (this.MapID != lockitem.MapID)
                {
                    thisMethod.BeginInvoke(null, null);
                    return;
                }
                //STATE IS VALID, CONTINUE EXECUTION///////////////////////////////////////////

                if (this.HP < 1)
                {
                    warmSpellCounter = 0;
                    return;
                }

                if (WarmSpell != null)
                    warmSpellCounter++;
                else
                    warmSpellCounter = 0;

                bool updateMyCreatureBase = false;
                bool updateHp = false;
                bool updateMana = false;
                bool updateStam = false;

                if (warmSpellCounter >= 3)
                {
                    this.Mana = this.Mana - 10;
                    updateMyCreatureBase = true;
                    updateMana = true;
                }

                if (this.HP >= this.MaxHP && this.Stamina >= this.MaxStamina && this.Mana >= this.MaxMana)
                    return;

                //Map CurrentMap = GameHandler.GetMap(MapID, Instance);
                List<Character> CharsToUpdate = new List<Character>();

                if (buffManager.GetBuff("Rabies") == null)
                {
                    if (this.HP < this.MaxHP)
                    {
                        this.HP = this.HP + HPRegen;
                        updateMyCreatureBase = true;
                        updateHp = true;
                    }

                    if (this.Mana < this.MaxMana && warmSpellCounter == 0)
                    {
                        this.Mana = this.Mana + ManaRegen;
                        updateMyCreatureBase = true;
                        updateMana = true;
                    }

                    if (this.Stamina < this.MaxStamina)
                    {
                        this.Stamina = this.Stamina + StaminaRegen;
                        updateMyCreatureBase = true;
                        updateStam = true;
                    }
                }

                if (updateMyCreatureBase == true)
                {
                    foreach (MapItem mapitem in currentMapItem.mapItemsWithin4)
                    {
                        if (mapitem.MapX - this.MapX >= -4 && mapitem.MapX - this.MapX <= 4 && mapitem.MapY - this.MapY >= -4 && mapitem.MapY - this.MapY <= 4)
                        {
                            foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                            {
                                if (creatureBase is Character)
                                {
                                    Character character = (Character)creatureBase;

                                    if (updateHp == true)
                                        character.UpdateCreatureBaseHp(this);
                                    if (updateStam == true)
                                        character.UpdateCreatureBaseStamina(this);
                                    if (updateMana == true)
                                        character.UpdateCreatureBaseMana(this);
                                }
                            }
                        }
                    }
                }
                if (this is Character && updateMyCreatureBase == true)
                {
                    Character character = (Character)this;
                    character.Update_Character();
                }
            }
            
        }

        //Timer Event, Character regen
        //private void Timer_Regen_Elapsed(object source, ElapsedEventArgs e)
        //{
        //    try
        //    {
        //        currentMapItem.parentMap.addMapJob((Action)runRegen, null);
        //    }
        //    catch { }
        //}

        //This is a convienence method so we dont have to keep checking if the creatureBase
        //is a character or not before updating.  This is overriden to do the update in the character subclass
        public virtual void Update_Character() { }

        public virtual void SendMessage(string msg, string type)
        {
            if (this is Character)
            {
                Character character = (Character)this;
                Message message = new Message();
                message.CreatureID = this.CreatureID;
                message.Type = type;
                message.Text = msg;

                character.AddMessage(message);
            }
        }

        public virtual void PlaySound(string Name, int MapX, int MapY)
        {

        }

        public void MessageBroadcast(List<MapItem> MapItems, Message message, bool sendToMe)
        {
            List<Point> hiddenList = CreatureAI.FindHidden(this, MapItems, true);

            foreach (MapItem mapitem in MapItems)
            {
                bool hasCharacters = false;
                foreach (CreatureBase creaturebase in mapitem.CreaturesBases)
                {
                    if (creaturebase is Character)
                    {
                        hasCharacters = true;
                        break;
                    }
                }
                if (hasCharacters == true && Math.Abs(mapitem.MapX - this.MapX) <= 4 && Math.Abs(mapitem.MapY - this.MapY) <= 4)
                {
                    bool isHidden = false;
                    foreach (Point point in hiddenList)
                    {
                        if (mapitem.MapX == point.X && mapitem.MapY == point.Y)
                        {
                            isHidden = true;
                            break;
                        }
                    }
                    if (isHidden == false)
                    {
                        foreach (CreatureBase creaturebase in mapitem.CreaturesBases)
                        {
                            if (creaturebase is Character && (creaturebase != this || sendToMe == true))
                            {
                                Character character = (Character)creaturebase;
                                character.AddMessage(message);
                            }
                        }
                    }
                }
            }
        }

        //Used to determine if this creature is visible to a different creature (does not account for hidden tiles)
        public bool CanSeeMe(CreatureBase creaturebase)
        {
            if (Math.Abs(creaturebase.MapX - MapX) > 1 || Math.Abs(creaturebase.MapY - MapY) > 1)
            {
                Spell_Hide hideBuff = (Spell_Hide)buffManager.GetBuffByStackType("Hide");
                if (hideBuff != null && hideBuff.canSeeThrough(creaturebase) == false)
                    return false;
            }
            if (buffManager.GetBuff("Invisibility") != null && creaturebase != this && creaturebase.buffManager.GetBuff("See Invisible") == null)
                return false;
            if (creaturebase is Creature && (this is Trainer || this is Banker || this is Vendor || this.CreatureType == "Binder" || this.CreatureType == "AlchemyTrainer"))
                return false;
            if (creaturebase is Creature && this is QuestCreature)
            {
                QuestCreature questCreature = (QuestCreature)this;
                if (questCreature.canSeeMe == false)
                    return false;
            }

            return true;
        }

        //Used to determine if 
        public virtual bool grantExpTo(Character character)
        {
            bool result = true;

            if (petController != null)
                result = false;

            if (this.CreatureType == "Binder" || this.CreatureType == "AlchemyTrainer")
                result = false;

            return result;
        }
    }
}
